package com.yerbamateprimer.action.user.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import com.google.common.base.Preconditions;
import com.yerbamateprimer.action.user.AsynchronousUserAction;
import com.yerbamateprimer.model.Group;
import com.yerbamateprimer.model.User;

/**
 * This action is useful
 * to send an invite users
 * to the round user action 
 * to the server.
 * 
 * @author Matias Liwski
 * @version 1.0
 */
public class InviteGroupsToRoundUserAction implements AsynchronousUserAction, Serializable {
	private static final long serialVersionUID = -8677336250473612266L;
	private User user;
	private Set<Group> invitedGroups;
	private Set<User> notInvitedUsers;

	/**
	 * @param user The user that want to execute this action.
	 * @param invitedGroups The groups to invite.
	 * @param notInvitedUsers The users from invited groups that don't want to invite.
	 */
	public InviteGroupsToRoundUserAction(User user, Collection<Group> invitedGroups, Collection<User> notInvitedUsers) {
		this.invitedGroups = new HashSet<Group>();
		this.notInvitedUsers = new HashSet<User>();
		
		setUser(user);
		addAllInvitedGroups(invitedGroups);
		addAllNotInvitedUsers(notInvitedUsers);
	}

	/**
	 * This class has to be implemented at the action decorator.
	 * 
	 * @see com.yerbamateprimer.action.user.UserAction#execute()
	 */
	public void execute() {
	}

	/* (non-Javadoc)
	 * @see com.yerbamateprimer.action.user.UserAction#setUser(com.yerbamateprimer.model.User)
	 */
	@Override
	public void setUser(User user) {
		Preconditions.checkArgument(user != null, "This action needs a user to execute it.");
		this.user = user;
	}
	

	/* (non-Javadoc)
	 * @see com.yerbamateprimer.action.user.UserAction#getUser()
	 */
	@Override
	public User getUser() {
		return this.user;
	}

	/**
	 * @param group The group to invite to the round, to add.
	 */
	public void addInvitedGroup(Group group) {
		Preconditions.checkArgument(group != null, "Couldn't add a null group.");
		Preconditions.checkArgument(group.getMembers().contains(user), "The inviting user "  + user + " has to belong to the group " + group + ".");
		this.invitedGroups.add(group);
	}

	/**
	 * @param groups The groups to invite to the round, to add.
	 */
	public void addAllInvitedGroups(Collection<Group> groups) {
		Preconditions.checkArgument(groups != null && !groups.isEmpty(), "Couldn't add an empty or null groups.");
		for (Group group : groups) {
			addInvitedGroup(group);
		}
	}

	/**
	 * @return A safe copy of the list of groups to invite.
	 */
	public Collection<Group> getInvitedGroups() {
		return new ArrayList<Group>(this.invitedGroups);
	}

	/**
	 * @param user The user from a group that wouldn't be invited, to add.
	 */
	public void addNotInvitedUser(User user) {
		Preconditions.checkArgument(user != null, "Couldn't add a null user to the list of not invited users.");
		this.notInvitedUsers.add(user);
	}

	/**
	 * @param users The list of users from groups that wouldn't be invited, to add.
	 */
	public void addAllNotInvitedUsers(Collection<User> users) {
		Preconditions.checkArgument(users != null, "The non invited users couldn't be null (Use empty list instead).");
		this.notInvitedUsers.addAll(users);
	}

	/**
	 * @return A safe copy of the list of users from groups that wouldn't be invited.
	 */
	public Collection<User> getNotInvitedUsers() {
		return new ArrayList<User>(this.notInvitedUsers);
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE, false, true);
	}
}